home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / news / inn1.000 / inn1.4sec-linux-src.tar / inn / innd / innd.c < prev    next >
C/C++ Source or Header  |  1993-03-18  |  20KB  |  893 lines

  1. /*  $Revision: 1.39 $
  2. **
  3. **  Variable definitions, miscellany, and main().
  4. */
  5. #define DEFINE_DATA
  6. #include "innd.h"
  7. #include <signal.h>
  8. #include <sys/ioctl.h>
  9. #include <sys/uio.h>
  10. #if    NOFILE_LIMIT > 0
  11. #include <sys/resource.h>
  12. #endif    /* NOFILE_LIMIT > 0 */
  13. #if    defined(DO_FAST_RESOLV)
  14. #include <arpa/nameser.h>
  15. #include <resolv.h>
  16. #endif    /* defined(DO_FAST_RESOLV) */
  17.  
  18.  
  19. #if    defined(HAVE_SETBUFFER)
  20. #define SETBUFFER(F, buff, size)    setbuffer((F), (buff), (size))
  21. STATIC int    LogBufferSize = 4096;
  22. #else
  23. #define SETBUFFER(F, buff, size)    setbuf((F), (buff))
  24. STATIC int    LogBufferSize = BUFSIZ;
  25. #endif    /* defined(HAVE_SETBUFFER) */
  26.  
  27.  
  28. BOOL        AmRoot = TRUE;
  29. BOOL        BufferedLogs = TRUE;
  30. BOOL        NNRPTracing = FALSE;
  31. BOOL        Tracing = FALSE;
  32. char        LogName[] = "ME";
  33. char        SPOOL[] = _PATH_SPOOL;
  34. int        ErrorCount = IO_ERROR_COUNT;
  35. int        MaxIncoming = DEFAULT_CONNECTIONS;
  36. int        SPOOLlen = STRLEN(SPOOL);
  37. long        LargestArticle = MAX_ART_SIZE;
  38. OPERATINGMODE    Mode = OMrunning;
  39. time_t        Cutoff = DEFAULT_CUTOFF * 24 * 60 * 60;
  40.  
  41. #if    defined(__CENTERLINE__)
  42. BOOL        Debug = TRUE;
  43. #else
  44. BOOL        Debug = FALSE;
  45. #endif    /* defined(__CENTERLINE__) */
  46.  
  47. #if    defined(lint) || defined(__CENTERLINE__)
  48. int        KeepLintQuiet = 0;
  49. #endif    /* defined(lint) || defined(__CENTERLINE__) */
  50.  
  51.  
  52. STATIC char    *ErrlogBuffer;
  53. STATIC char    *LogBuffer;
  54. STATIC char    ERRLOG[] = _PATH_ERRLOG;
  55. STATIC char    INNDDIR[] = _PATH_INNDDIR;
  56. STATIC char    LOG[] = _PATH_LOGFILE;
  57. STATIC char    PID[] = _PATH_SERVERPID;
  58. STATIC UID_T    NewsUID;
  59. STATIC GID_T    NewsGID;
  60.  
  61.  
  62.  
  63. /*
  64. **  Sprintf a long into a buffer with enough leading zero's so that it
  65. **  takes up width characters.  Don't add trailing NUL.  Return TRUE
  66. **  if it fit.  Used for updating high-water marks in the active file
  67. **  in-place.
  68. */
  69. BOOL
  70. FormatLong(p, value, width)
  71.     register char    *p;
  72.     register long    value;
  73.     register int    width;
  74. {
  75.     for (p += width - 1; width-- > 0; ) {
  76.     *p-- = (int)(value % 10) + '0';
  77.     value /= 10;
  78.     }
  79.     return value == 0;
  80. }
  81.  
  82.  
  83. /*
  84. **  Glue a string, a char, and a string together.  Useful for making
  85. **  filenames.
  86. */
  87. void
  88. FileGlue(p, n1, c, n2)
  89.     register char    *p;
  90.     register char    *n1;
  91.     char        c;
  92.     register char    *n2;
  93. {
  94.     p += strlen(strcpy(p, n1));
  95.     *p++ = c;
  96.     (void)strcpy(p, n2);
  97. }
  98.  
  99.  
  100. /*
  101. **  Turn any \r or \n in text into spaces.  Used to splice back multi-line
  102. **  headers into a single line.
  103. */
  104. STATIC char *
  105. Join(text)
  106.     register char    *text;
  107. {
  108.     register char    *p;
  109.  
  110.     for (p = text; *p; p++)
  111.     if (*p == '\n' || *p == '\r')
  112.         *p = ' ';
  113.     return text;
  114. }
  115.  
  116.  
  117. /*
  118. **  Return a short name that won't overrun our bufer or syslog's buffer.
  119. **  q should either be p, or point into p where the "interesting" part is.
  120. */
  121. char *
  122. MaxLength(p, q)
  123.     char        *p;
  124.     char        *q;
  125. {
  126.     static char        buff[80];
  127.     register int    i;
  128.  
  129.     /* Already short enough? */
  130.     i = strlen(p);
  131.     if (i < sizeof buff - 1)
  132.     return Join(p);
  133.  
  134.     /* Simple case of just want the begining? */
  135.     if (q - p < sizeof buff - 4) {
  136.     (void)strncpy(buff, p, sizeof buff - 4);
  137.     (void)strcpy(&buff[sizeof buff - 4], "...");
  138.     }
  139.     /* Is getting last 10 characters good enough? */
  140.     else if ((p + i) - q < 10) {
  141.     (void)strncpy(buff, p, sizeof buff - 14);
  142.     (void)strcpy(&buff[sizeof buff - 14], "...");
  143.     (void)strcpy(&buff[sizeof buff - 11], &p[i - 10]);
  144.     }
  145.     else {
  146.     /* Not in last 10 bytes, so use double elipses. */
  147.     (void)strncpy(buff, p, sizeof buff - 17);
  148.     (void)strcpy(&buff[sizeof buff - 17], "...");
  149.     (void)strncpy(&buff[sizeof buff - 14], &q[-5], 10);
  150.     (void)strcpy(&buff[sizeof buff - 4], "...");
  151.     }
  152.     return Join(buff);
  153. }
  154.  
  155.  
  156. /*
  157. **  Split text into comma-separated fields.  Return an allocated
  158. **  NULL-terminated array of the fields within the modified argument that
  159. **  the caller is expected to save or free.  We don't use strchr() since
  160. **  the text is expected to be either relatively short or "comma-dense."
  161. */
  162. char **
  163. CommaSplit(text)
  164.     char        *text;
  165. {
  166.     register int    i;
  167.     register char    *p;
  168.     register char    **av;
  169.     char        **save;
  170.  
  171.     /* How much space do we need? */
  172.     for (i = 2, p = text; *p; p++)
  173.     if (*p == ',')
  174.         i++;
  175.  
  176.     for (av = save = NEW(char*, i), *av++ = p = text; *p; )
  177.     if (*p == ',') {
  178.         *p++ = '\0';
  179.         *av++ = p;
  180.     }
  181.     else
  182.         p++;
  183.     *av = NULL;
  184.     return save;
  185. }
  186.  
  187.  
  188. /*
  189. **  Do we need a shell for the command?  If not, av is filled in with
  190. **  the individual words of the command and the command is modified to
  191. **  have NUL's inserted.
  192. */
  193. BOOL
  194. NeedShell(p, av, end)
  195.     register char    *p;
  196.     register char    **av;
  197.     register char    **end;
  198. {
  199.     static char        Metachars[] = ";<>|*?[]{}()#$&=`'\"\\~\n";
  200.     register char    *q;
  201.  
  202.     /* We don't use execvp(); works for users, fails out of /etc/rc. */
  203.     if (*p != '/')
  204.     return TRUE;
  205.     for (q = p; *q; q++)
  206.     if (strchr(Metachars, *q) != NULL)
  207.         return TRUE;
  208.  
  209.     for (end--; av < end; ) {
  210.     /* Mark this word, check for shell meta-characters. */
  211.     for (*av++ = p; *p && !ISWHITE(*p); p++)
  212.         continue;
  213.  
  214.     /* If end of list, we're done. */
  215.     if (*p == '\0') {
  216.         *av = NULL;
  217.         return FALSE;
  218.     }
  219.  
  220.     /* Skip whitespace, find next word. */
  221.     for (*p++ = '\0'; ISWHITE(*p); p++)
  222.         continue;
  223.     if (*p == '\0') {
  224.         *av = NULL;
  225.         return FALSE;
  226.     }
  227.     }
  228.  
  229.     /* Didn't fit. */
  230.     return TRUE;
  231. }
  232.  
  233.  
  234. /*
  235. **  Spawn a process, with I/O redirected as needed.  Return the PID or -1
  236. **  (and a syslog'd message) on error.
  237. */
  238. int
  239. Spawn(fd0, fd1, fd2, av)
  240.     int        fd0;
  241.     int        fd1;
  242.     int        fd2;
  243.     char    *av[];
  244. {
  245.     static char    NOCLOSE[] = "%s cant close %d in %s %m";
  246.     static char    NODUP2[] = "%s cant dup2 %d to %d in %s %m";
  247.     int        i;
  248.  
  249.     /* Fork; on error, give up.  If not using the patched dbz, make
  250.      * this call fork! */
  251.     i = FORK();
  252.     if (i == -1) {
  253.     syslog(L_ERROR, "%s cant fork %s %m", LogName, av[0]);
  254.     return -1;
  255.     }
  256.  
  257.     /* If parent, do nothing. */
  258.     if (i > 0)
  259.     return i;
  260.  
  261.     /* Child -- do any I/O redirection. */
  262.     if (fd0 != 0) {
  263.     if (dup2(fd0, 0) < 0) {
  264.         syslog(L_FATAL, NODUP2, LogName, fd0, 0, av[0]);
  265.         _exit(1);
  266.     }
  267.     if (fd0 != fd1 && fd0 != fd2 && close(fd0) < 0)
  268.         syslog(L_ERROR, NOCLOSE, LogName, fd0, av[0]);
  269.     }
  270.     if (fd1 != 1) {
  271.     if (dup2(fd1, 1) < 0) {
  272.         syslog(L_FATAL, NODUP2, LogName, fd1, 1, av[0]);
  273.         _exit(1);
  274.     }
  275.     if (fd1 != fd2 && close(fd1) < 0)
  276.         syslog(L_ERROR, NOCLOSE, LogName, fd1, av[0]);
  277.     }
  278.     if (fd2 != 2) {
  279.     if (dup2(fd2, 2) < 0) {
  280.         syslog(L_FATAL, NODUP2, LogName, fd2, 2, av[0]);
  281.         _exit(1);
  282.     }
  283.     if (close(fd2) < 0)
  284.         syslog(L_ERROR, NOCLOSE, LogName, fd2, av[0]);
  285.     }
  286.     CloseOnExec(0, FALSE);
  287.     CloseOnExec(1, FALSE);
  288.     CloseOnExec(2, FALSE);
  289.  
  290.     /* Try to set our permissions. */
  291. #if    defined(DO_INND_NICE_KIDS)
  292.     (void)nice(INND_NICE_VALUE);
  293. #endif    /* defined(DO_INND_NICE_KIDS) */
  294.     if (setgid(NewsGID) == -1)
  295.     syslog(L_ERROR, "%s cant setgid in %s %m", LogName, av[0]);
  296.     if (setuid(NewsUID) == -1)
  297.     syslog(L_ERROR, "%s cant setuid in %s %m", LogName, av[0]);
  298.  
  299.     /* Close the DBZ database without doing any writing. */
  300.     /* Not needed with the patched DBZ; can't be used with vfork.
  301.      * (void)dbzcancel();
  302.      * (void)dbmclose();
  303.      */
  304.  
  305.     /* Start the desired process (finally!). */
  306.     (void)execv(av[0], av);
  307.     syslog(L_FATAL, "%s cant exec in %s %m", LogName, av[0]);
  308.     _exit(1);
  309.     /* NOTREACHED */
  310. }
  311.  
  312.  
  313. /*
  314. **  Stat our control directory and see who should own things.
  315. */
  316. STATIC BOOL
  317. GetNewsOwnerships()
  318. {
  319.     struct stat    Sb;
  320.  
  321.     /* Make sure item exists and is of the right type. */
  322.     if (stat(INNDDIR, &Sb) < 0)
  323.     return FALSE;
  324.     if (!S_ISDIR(Sb.st_mode))
  325.     return FALSE;
  326.     NewsUID = Sb.st_uid;
  327.     NewsGID = Sb.st_gid;
  328.     return TRUE;
  329. }
  330.  
  331.  
  332. /*
  333. **  Change the onwership of a file.
  334. */
  335. void
  336. xchown(p)
  337.     char    *p;
  338. {
  339.     if (chown(p, NewsUID, NewsGID) < 0)
  340.     syslog(L_ERROR, "%s cant chown %s %m", LogName, p);
  341. }
  342.  
  343.  
  344. /*
  345. **  Try to make one directory.  Return FALSE on error.
  346. */
  347. STATIC BOOL
  348. MakeDir(Name)
  349.     char        *Name;
  350. {
  351.     struct stat        Sb;
  352.  
  353.     if (mkdir(Name, GROUPDIR_MODE) >= 0) {
  354.     if (AmRoot)
  355.         xchown(Name);
  356.     return TRUE;
  357.     }
  358.  
  359.     /* See if it failed because it already exists. */
  360.     return stat(Name, &Sb) >= 0 && S_ISDIR(Sb.st_mode);
  361. }
  362.  
  363.  
  364. /*
  365. **  Given a directory, comp/foo/bar, create that directory and all
  366. **  intermediate directories needed.  Return 0 if ok, else -1.
  367. */
  368. BOOL
  369. MakeSpoolDirectory(Name)
  370.     register char    *Name;
  371. {
  372.     register char    *p;
  373.     BOOL        made;
  374.  
  375.     /* Optimize common case -- parent almost always exists. */
  376.     if (MakeDir(Name))
  377.     return TRUE;
  378.  
  379.     /* Try to make each of comp and comp/foo in turn. */
  380.     for (p = Name; *p; p++)
  381.     if (*p == '/') {
  382.         *p = '\0';
  383.         made = MakeDir(Name);
  384.         *p = '/';
  385.         if (!made)
  386.         return FALSE;
  387.     }
  388.  
  389.     return MakeDir(Name);
  390. }
  391.  
  392.  
  393. /*
  394. **  Flush one log file, with pessimistic size of working filename buffer.
  395. */
  396. void
  397. ReopenLog(F)
  398.     FILE    *F;
  399. {
  400.     char    buff[sizeof LOG + sizeof ERRLOG + 4 + 1];
  401.     char    *Name;
  402.     char    *Buffer;
  403.     int        mask;
  404.     
  405.     if (Debug)
  406.     return;
  407.     if (F == Log) {
  408.     Name = LOG;
  409.     Buffer = LogBuffer;
  410.     }
  411.     else {
  412.     Name = ERRLOG;
  413.     Buffer = ErrlogBuffer;
  414.     }
  415.  
  416.     FileGlue(buff, Name, '.', "old");
  417.     if (rename(Name, buff) < 0)
  418.     syslog(L_ERROR, "%s cant rename %s to %s %m", LogName, Name, buff);
  419.     mask = umask(033);
  420.     if (freopen(Name, "a", F) != F) {
  421.     syslog(L_FATAL, "%s cant freopen %s %m", LogName, Name);
  422.     exit(1);
  423.     }
  424.     (void)umask(mask);
  425.     if (AmRoot)
  426.     xchown(Name);
  427.     if (BufferedLogs)
  428.     SETBUFFER(F, Buffer, LogBufferSize);
  429. }
  430.  
  431.  
  432. /*
  433. **  Function called when memory allocation fails.
  434. */
  435. STATIC int
  436. AllocationFailure(what, i)
  437.     char        *what;
  438.     unsigned int    i;
  439. {
  440.     /* Print i as %d so huge values are real obvious. */
  441.     syslog(L_FATAL, "%s cant %s %d bytes %m", LogName, what, i);
  442.     exit(1);
  443.     /* NOTREACHED */
  444. }
  445.  
  446.  
  447. /*
  448. **  We ran out of space or other I/O error, throttle ourselves.
  449. */
  450. void
  451. ThrottleIOError(when)
  452.     char    *when;
  453. {
  454.     char    buff[SMBUF];
  455.     STRING    p;
  456.     int        oerrno;
  457.  
  458.     if (Mode == OMrunning) {
  459.     oerrno = errno;
  460.     if (Reservation) {
  461.         DISPOSE(Reservation);
  462.         Reservation = NULL;
  463.     }
  464.     (void)sprintf(buff, "%s writing %s file -- throttling",
  465.         strerror(oerrno), when);
  466.     if ((p = CCblock(OMthrottled, buff)) != NULL)
  467.         syslog(L_ERROR, "%s cant throttle %s", LogName, p);
  468.     syslog(L_FATAL, "%s throttle %s", LogName, buff);
  469.     errno = oerrno;
  470.     }
  471. }
  472.  
  473.  
  474. /*
  475. **  Close down all parts of the system (e.g., before calling exit or exec).
  476. */
  477. void
  478. JustCleanup()
  479. {
  480.     SITEflushall(FALSE);
  481.     /* PROCclose(FALSE); */
  482.     CCclose();
  483.     LCclose();
  484.     NCclose();
  485.     RCclose();
  486.     ICDclose();
  487.     HISclose();
  488.     ARTclose();
  489.     (void)sleep(1);
  490.     /* PROCclose(TRUE); */
  491.     if (unlink(PID) < 0 && errno != ENOENT)
  492.     syslog(L_ERROR, "%s cant unlink %s %m", LogName, PID);
  493. }
  494.  
  495.  
  496. /*
  497. **  The name is self-explanatory.
  498. */
  499. NORETURN
  500. CleanupAndExit(x, why)
  501.     int        x;
  502.     char    *why;
  503. {
  504.     JustCleanup();
  505.     syslog(L_NOTICE, "%s shutdown %s", LogName, why);
  506.     exit(x);
  507. }
  508.  
  509.  
  510. #if    NOFILE_LIMIT > 0
  511. /*
  512. **  Set the limit on the number of open files we can have.  I don't
  513. **  like having to do this.
  514. */
  515. STATIC void
  516. SetDescriptorLimit(i)
  517.     int            i;
  518. {
  519.     struct rlimit    rl;
  520.  
  521.     if (getrlimit(RLIMIT_NOFILE, &rl) < 0) {
  522.     syslog(L_ERROR, "%s cant getrlimit(NOFILE) %m", LogName);
  523.     return;
  524.     }
  525.     rl.rlim_cur = i;
  526.     if (setrlimit(RLIMIT_NOFILE, &rl) < 0) {
  527.     syslog(L_ERROR, "%s cant setrlimit(NOFILE) %d %m", LogName, i);
  528.     return;
  529.     }
  530. }
  531. #endif    /* NOFILE_LIMIT > 0 */
  532.  
  533.  
  534. /*
  535. **  Signal handler to catch SIGTERM and queue a clean shutdown.
  536. */
  537. STATIC SIGHANDLER
  538. CatchTerminate(s)
  539.     int        s;
  540. {
  541.     GotTerminate = TRUE;
  542.     (void)signal(s, CatchTerminate);
  543. }
  544.  
  545.  
  546. /*
  547. **  Print a usage message and exit.
  548. */
  549. STATIC NORETURN
  550. Usage()
  551. {
  552.     (void)fprintf(stderr, "Usage error.\n");
  553.     exit(1);
  554. }
  555.  
  556.  
  557. int
  558. main(ac, av)
  559.     int            ac;
  560.     char        *av[];
  561. {
  562.     static char        WHEN[] = "PID file";
  563.     int            i;
  564.     int            port;
  565.     int            logflags;
  566.     char        buff[SMBUF];
  567.     char        *master;
  568.     STRING        path;
  569.     STRING        p;
  570.     FILE        *F;
  571.     BOOL        ShouldFork;
  572.     BOOL        ShouldRenumber;
  573.     BOOL        ShouldSyntaxCheck;
  574.     long        pid;
  575. #if    defined(_DEBUG_MALLOC_INC)
  576.     union malloptarg    m;
  577. #endif    /* defined(_DEBUG_MALLOC_INC) */
  578.  
  579.     /* Set up the pathname, first thing. */
  580.     path = av[0];
  581.     if (path == NULL || *path == '\0')
  582.     path = "innd";
  583.     else if ((p = strrchr(path, '/')) != NULL)
  584.     path = p + 1;
  585.     ONALLLOCFAIL(AllocationFailure);
  586.     Version = INNVersion();
  587.  
  588.     /* Handle malloc debugging. */
  589. #if    defined(_DEBUG_MALLOC_INC)
  590.     m.i = M_HANDLE_ABORT;
  591.     dbmallopt(MALLOC_WARN, &m);
  592.     dbmallopt(MALLOC_FATAL, &m);
  593.     m.i = 3;
  594.     dbmallopt(MALLOC_FILLAREA, &m);
  595.     m.i = 0;
  596.     dbmallopt(MALLOC_CKCHAIN, &m);
  597.     dbmallopt(MALLOC_CKDATA, &m);
  598. #endif    /* defined(_DEBUG_MALLOC_INC) */
  599.  
  600.     /* Set defaults. */
  601.     TimeOut.tv_sec = DEFAULT_TIMEOUT;
  602.     ShouldFork = TRUE;
  603.     ShouldRenumber = FALSE;
  604.     ShouldSyntaxCheck = FALSE;
  605.     logflags = L_OPENLOG_FLAGS | LOG_NOWAIT;
  606.     port = -1;
  607.     master = NULL;
  608. #if    defined(DONT_ALLOW_READERS)
  609.     NNRPFollows = TRUE;
  610. #endif    /* defined(DONT_ALLOW_READERS) */
  611.  
  612. #if    defined(DO_FAST_RESOLV)
  613.     /* We only use FQDN's in the hosts.nntp file. */
  614.     _res.options &= ~(RES_DEFNAMES | RES_DNSRCH);
  615. #endif    /* defined(DO_FAST_RESOLV) */
  616.  
  617.     /* Parse JCL. */
  618.     CCcopyargv(av);
  619.     while ((i = getopt(ac, av, "ac:dfi:l:m:o:n:p:rsS:t:ux")) != EOF)
  620.     switch (i) {
  621.     default:
  622.         Usage();
  623.         /* NOTREACHED */
  624.     case 'a':
  625.         AnyIncoming = TRUE;
  626.         break;
  627.     case 'c':
  628.         Cutoff = atoi(optarg) * 24 * 60 * 60;
  629.         break;
  630.     case 'd':
  631.         Debug = TRUE;
  632. #if    defined(LOG_PERROR)
  633.         logflags = LOG_PERROR | (logflags & ~LOG_CONS);
  634. #endif    /* defined(LOG_PERROR) */
  635.         break;
  636.     case 'f':
  637.         ShouldFork = FALSE;
  638.         break;
  639.     case 'i':
  640.         MaxIncoming = atoi(optarg);
  641.         break;
  642.     case 'l':
  643.         LargestArticle = atol(optarg);
  644.         break;
  645.     case 'm':
  646.         if (ModeReason)
  647.         DISPOSE(ModeReason);
  648.         switch (*optarg) {
  649.         default:
  650.         Usage();
  651.         /* NOTREACHED */
  652.         case 'g':    Mode = OMrunning;    break;
  653.         case 'p':    Mode = OMpaused;    break;
  654.         case 't':    Mode = OMthrottled;    break;
  655.         }
  656.         if (Mode != OMrunning) {
  657.         (void)sprintf(buff, "%sed from command line",
  658.             Mode == OMpaused ? "Paus" : "Throttl");
  659.         ModeReason = COPY(buff);
  660.         }
  661.         break;
  662.     case 'n':
  663.         switch (*optarg) {
  664.         default:
  665.         Usage();
  666.         /* NOTREACHED */
  667.         case 'n':    NNRPFollows = TRUE;    break;
  668.         case 'y':    NNRPFollows = FALSE;    break;
  669.         }
  670.         break;
  671.     case 'o':
  672.         MaxOutgoing = atoi(optarg);
  673.         break;
  674.     case 'p':
  675.         /* Silently ignore multiple -p flags, in case ctlinnd xexec
  676.          * called inndstart. */
  677.         if (port == -1) {
  678.         port = atoi(optarg);
  679.         AmRoot = FALSE;
  680.         }
  681.         break;
  682.     case 'r':
  683.         ShouldRenumber = TRUE;
  684.         break;
  685.     case 's':
  686.         ShouldSyntaxCheck = TRUE;
  687.         break;
  688.     case 'S':
  689.         master = optarg;
  690.         break;
  691.     case 't':
  692.         TimeOut.tv_sec = atol(optarg);
  693.         break;
  694.     case 'u':
  695.         BufferedLogs = FALSE;
  696.         break;
  697.     case 'x':
  698.         AlwaysCrosspost = TRUE;
  699.         break;
  700.     }
  701.     ac -= optind;
  702.     if (ac != 0)
  703.     Usage();
  704.     if (ModeReason && NNRPFollows)
  705.     NNRPReason = COPY(ModeReason);
  706.  
  707.     openlog(path, logflags, LOG_INN_SERVER);
  708.  
  709.     if (ShouldSyntaxCheck) {
  710.     if ((p = CCcheckfile((char **)NULL)) == NULL)
  711.         exit(0);
  712.     (void)fprintf(stderr, "%s\n", p + 2);
  713.     }
  714.  
  715.     /* Go to where the data is. */
  716.     if (chdir(SPOOL) < 0) {
  717.     syslog(L_FATAL, "%s cant chdir %s %m", LogName, SPOOL);
  718.     exit(1);
  719.     }
  720.  
  721.     /* Get the Path entry. */
  722.     if ((path = GetConfigValue(_CONF_PATHHOST)) == NULL) {
  723.     syslog(L_FATAL, "%s cant GetConfigValue %s %m",
  724.         LogName, _CONF_PATHHOST);
  725.     exit(1);
  726.     }
  727.     Path.Used = strlen(path) + 1;
  728.     Path.Data = NEW(char, Path.Used + 1);
  729.     (void)sprintf(Path.Data, "%s!", path);
  730.  
  731.     /* Get the Xref prefix. */
  732.     Xref.Size = SMBUF;
  733.     Xref.Data = NEW(char, Xref.Size);
  734.     (void)sprintf(Xref.Data, "Xref: %s", path);
  735.     Xref.Used = strlen(Xref.Data);
  736.     Xrefbase = Xref.Used;
  737.  
  738. #if    !defined(__CENTERLINE__)
  739.     /* Set standard input to /dev/null. */
  740.     if ((i = open("/dev/null", O_RDWR)) < 0) {
  741.     syslog(L_FATAL, "%s cant open /dev/null %m", LogName);
  742.     exit(1);
  743.     }
  744.     if (dup2(i, 0) != 0)
  745.     syslog(L_NOTICE, "%s cant dup2 %d to 0 %m", LogName, i);
  746.     (void)close(i);
  747. #endif    /* !defined(__CENTERLINE__) */
  748.  
  749.     /* Set up our permissions. */
  750.     (void)umask(NEWSUMASK);
  751.     if (!GetNewsOwnerships()) {
  752.     syslog(L_FATAL, "%s internal cant stat control directory %m", LogName);
  753.     exit(1);
  754.     }
  755.     if (port != -1 && setgid(NewsGID) < 0)
  756.     syslog(L_ERROR, "%s cant setgid running as %d not %d %m",
  757.         LogName, (int)getgid(), (int)NewsGID);
  758.  
  759.     if (Debug) {
  760.     Log = stdout;
  761.     Errlog = stderr;
  762.     (void)signal(SIGINT, CatchTerminate);
  763.     }
  764.     else {
  765.     if (ShouldFork) {
  766.         /* Become a server. */
  767.         i = fork();
  768.         if (i < 0) {
  769.         syslog(L_FATAL, "%s cant fork %m", LogName);
  770.         exit(1);
  771.         }
  772.         if (i > 0)
  773.         _exit(0);
  774.  
  775. #if    defined(TIOCNOTTY)
  776.         /* Disassociate from terminal. */
  777.         if ((i = open("/dev/tty", O_RDWR)) >= 0) {
  778.         if (ioctl(i, TIOCNOTTY, (char *)NULL) < 0)
  779.             syslog(L_ERROR, "%s cant ioctl(TIOCNOTTY) %m", LogName);
  780.         if (close(i) < 0)
  781.             syslog(L_ERROR, "%s cant close /dev/tty %m", LogName);
  782.         }
  783. #endif    /* defined(TIOCNOTTY) */
  784. #if    defined(DO_HAVE_SETSID)
  785.         (void)setsid();
  786. #endif    /* defined(DO_HAVE_SETSID) */
  787.     }
  788.  
  789.     /* Open the Log. */
  790.     (void)fclose(stdout);
  791.     if ((Log = fopen(LOG, "a")) == NULL) {
  792.         syslog(L_FATAL, "%s cant fopen %s %m", LogName, LOG);
  793.         exit(1);
  794.     }
  795.     if (AmRoot)
  796.         xchown(LOG);
  797.     if (BufferedLogs && (LogBuffer = NEW(char, LogBufferSize)) != NULL)
  798.         SETBUFFER(Log, LogBuffer, LogBufferSize);
  799.  
  800.     /* Open the Errlog. */
  801.     (void)fclose(stderr);
  802.     if ((Errlog = fopen(ERRLOG, "a")) == NULL) {
  803.         syslog(L_FATAL, "%s cant fopen %s %m", LogName, ERRLOG);
  804.         exit(1);
  805.     }
  806.     if (AmRoot)
  807.         xchown(ERRLOG);
  808.     if (BufferedLogs && (ErrlogBuffer = NEW(char, LogBufferSize)) != NULL)
  809.         SETBUFFER(Errlog, ErrlogBuffer, LogBufferSize);
  810.     }
  811.  
  812.     /* Set number of open channels. */
  813. #if    NOFILE_LIMIT > 0
  814.     if (AmRoot)
  815.     SetDescriptorLimit(NOFILE_LIMIT);
  816. #endif    /* NOFILE_LIMIT > 0 */
  817.     /* Get number of open channels. */
  818.     if ((i = getfdcount()) < 0) {
  819.     syslog(L_FATAL, "%s cant getfdcount %m", LogName);
  820.     exit(1);
  821.     }
  822.     syslog(L_NOTICE, "%s descriptors %d", LogName, i);
  823.     if (MaxOutgoing == 0) {
  824.     /* getfdcount() - (stdio + dbz + cc + lc + rc + art + fudge) */
  825.     MaxOutgoing = i - (  3   +  3  +  2 +  1 +  1 +  1  +   2  );
  826.     syslog(L_NOTICE, "%s outgoing %d", LogName, MaxOutgoing);
  827.     }
  828.  
  829.     /* See if another instance is alive. */
  830.     if ((F = fopen(PID, "r")) != NULL) {
  831.     if (fgets(buff, sizeof buff, F) != NULL
  832.      && ((pid = atoi(buff)) > 0)
  833.      && (kill((PID_T)pid, 0) > 0 || errno != ESRCH)) {
  834.         (void)syslog(L_FATAL, "%s already_running pid %d", LogName, pid);
  835.         exit(1);
  836.     }
  837.     (void)fclose(F);
  838.     }
  839.  
  840.     /* Set up the various parts of the system.  Channel feeds start
  841.      * processes so call PROCsetup before ICDsetup.  NNTP needs to know
  842.      * if it's a slave, so call RCsetup before NCsetup. */
  843.     (void)signal(SIGTERM, CatchTerminate);
  844. #if    defined(SIGDANGER)
  845.     (void)signal(SIGDANGER, CatchTerminate);
  846. #endif    /* defined(SIGDANGER) */
  847.     CHANsetup(i);
  848.     PROCsetup(i * 2);
  849.     HISsetup();
  850.     CCsetup();
  851.     LCsetup();
  852.     RCsetup(port, master);
  853.     NCsetup(i);
  854.     ARTsetup();
  855.     ICDsetup(TRUE);
  856. #if    defined(_DEBUG_MALLOC_INC)
  857.     m.i = 1;
  858.     dbmallopt(MALLOC_CKCHAIN, &m);
  859.     dbmallopt(MALLOC_CKDATA, &m);
  860. #endif    /* defined(_DEBUG_MALLOC_INC) */
  861.  
  862.     /* Record our PID. */
  863.     pid = getpid();
  864.     if ((F = fopen(PID, "w")) == NULL) {
  865.     IOError(WHEN);
  866.     syslog(L_ERROR, "%s cant fopen %s %m", LogName, PID);
  867.     }
  868.     else {
  869.     if (fprintf(F, "%ld\n", (long)pid) == EOF || ferror(F)) {
  870.         IOError(WHEN);
  871.         syslog(L_ERROR, "%s cant fprintf %s %m", LogName, PID);
  872.     }
  873.     if (fclose(F) == EOF) {
  874.         IOError(WHEN);
  875.         syslog(L_ERROR, "%s cant fclose %s %m", LogName, PID);
  876.     }
  877.     if (chmod(PID, 0664) < 0) {
  878.         IOError(WHEN);
  879.         syslog(L_ERROR, "%s cant chmod %s %m", LogName, PID);
  880.     }
  881.     }
  882.  
  883.     /* And away we go... */
  884.     if (ShouldRenumber) {
  885.     syslog(L_NOTICE, "%s renumbering", LogName);
  886.     ICDrenumberactive();
  887.     }
  888.     syslog(L_NOTICE, "%s starting", LogName);
  889.     CHANreadloop();
  890.     CleanupAndExit(1, "CHANreadloop returned");
  891.     /* NOTREACHED */
  892. }
  893.